#!/usr/local/bin/perl -w
#
# BBX.Log.Analyzer.Alpha.bla.pl.v.1.4
# MAIN PROGRAM
# REQUIRED FILES: Acme/Include.pm, config.pl
# May 08, 2009
#
# DO NOT MODIFY THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING
#push(@INC, '/home/ecastmyhome/www/cgi-bin/Acme/Include.pm');
use lib '/home/ecastmyhome/www/cgi-bin';
use strict;
use DBI;
use DateTime;
use warnings;
use Acme::Include;
use File::Copy;

##== GLOBAL SETTINGS (Do not change here, change in config.pl!) ==#
##----------------------------------------------------------------#
# Initialize Globals
our $securityLog = 0;
our $dailyLog = 0;
our $mysqlRootUsername = 0;
our $mysqlRootPassword = 0;
our $mysqlRootDatabase = 0;
our $mysqlRoot = 0;
our $mysqlDatabase = 0;
our $mysqlUsername = 0;
our $mysqlPassword = 0;
our $domain = 0;
our $adminEmail = 0;
our $periodicReportsParser = 0;
our $emailMod = 0;
our $intrusionMod = 0;
our $userMod = 0;
our $cleanDat = 0;
our $reportDir = "";
our @dailyLogErrors = (0);
our @securityLogErrors = (0);
# Set globas using config file
include '/home/ecastmyhome/www/cgi-bin/config.pl';
##----------------------------#
##== END OF GLOBAL SETTINGS ==#

our $successfulClean = 0;
our $numberOfEmails = 0;
our $numBadAddresses = 0;
my $datestring = prettydate(); 

print $datestring; 

open (outputDat, ">runOutput.html") or die "$!\n";
print outputDat "<html><head><title>bbxLogAnalyzer Last Run</title></head><body><pre>";
print outputDat "<h3>BBX Log Analyzer - Latest run verification</h3>";
print outputDat "<h4>". $datestring ."</h4>";

our $dbh =DBI->connect("dbi:mysql:$mysqlDatabase",$mysqlUsername,$mysqlPassword)
              or die "Connection Error: $DBI::errstr\n";

$dbh->do("CREATE TABLE errorCodes (
          id int AUTO_INCREMENT NOT NULL,
          errorNumber int(4) UNIQUE,
          errorDescripion text,
          actionTaken text,
          recommendedAction text,
          PRIMARY KEY (id),
          FULLTEXT (errorDescripion),
          FULLTEXT (actionTaken),
          FULLTEXT (recommendedAction)
          );")
      or die "Connection Error: $DBI::errstr\n";

$dbh->do("CREATE TABLE errorCodesNum (
          id int AUTO_INCREMENT NOT NULL,
          errorNumber int(4),
          month int(2),
          year int(2),
          time varchar(20),
          number int(5),
          PRIMARY KEY (id)
          );")
      or die "Connection Error: $DBI::errstr\n";

sub prettydate { 
   @_ = localtime(shift || time); 
   return(sprintf("%02d:%02d %02d/%02d/%04d", @_[2,1], $_[4]+1, $_[3], $_[5]+1900)); 
}

### EMAIL MODULE ###
# DESIGNED TO MAINTAIN EMAIL DATABASES 
# THIS IS A FAIRLY SPECIFIC MODULE BUT IT COULD BE EASILY 
# ALTERED TO DO MANY THINGS
sub emailMod
{
  my $e = 0;
  my $datFile = 0;
  my $email = 0;
  my $dt = 0;
  my $month = 0;
  my $year = 0;
  my $time = 0;
  my $sql = 0;
  my $sth = 0;
  my $salutation = 0;
  my $first = 0;
  my $last = 0;
  my $count = 0;

  foreach $e (@dailyLogErrors){
    $datFile = $e->[0] . ".dat";
    eval("sub matches { return \$_[0] =~ $e->[1]; }");
    # CREATE DATA FILE
    open (badData, ">".$datFile) or die "$!\n";
    open (inputDat, $dailyLog) or die "$!\n";
    $count = 0;
    while (<inputDat>){
      chomp;
      if(matches($_)){
        $email = <inputDat>;
        chomp;
        $email =~ s/^ *//;
        print badData $email;
        $count++;
      }
    }
    close (badData);
    close (inputDat);
  
    $dt = DateTime->now;
    $month = $dt->month;
    $year = $dt->year;
    $time = time;
    $sql = "INSERT INTO errorCodesNum VALUES(?,?,?,?,?,?)";
    $sth = $dbh->prepare($sql) or die "Prepare Error: $DBI::errstr\n";
    $sth->execute('NULL',$e->[2],$month,$year,$time,$count)
    or die "SQL Error: $DBI::errstr\n";  
    
    # CREATE AND POPULATE MYSQL TABLES
    open (inputDat, $datFile) or die "$!\n";
               
    $dbh->do("CREATE TABLE " . $e->[0] . " (
              id INT AUTO_INCREMENT NOT NULL, 
              email VARCHAR(100),
              salutation VARCHAR(80),
              fname VARCHAR(50), 
              lname VARCHAR(40),
              PRIMARY KEY (id))") 
          or die "Connection Error: $DBI::errstr\n";
  
    $sql = "INSERT INTO errorCodes VALUES(?,?,?,?,?)";
    $sth = $dbh->prepare($sql) or die "Prepare Error: $DBI::errstr\n";
    $sth->execute('NULL',$e->[2],$e->[3],$e->[4],$e->[5])
    or die "SQL Error: $DBI::errstr\n";
  
    while (<inputDat>){
      chomp;
      $email = $_;
      $sql = "SELECT * FROM contacts WHERE email='$email'";
      $sth = $dbh->prepare($sql) or die "Prepare Error: $DBI::errstr\n";
      $sth->execute() or die "SQL Error: $DBI::errstr\n";
  
      while(my @row = $sth->fetchrow_array){
        $salutation = $row[2];
        $first = $row[3];
        $last = $row[4];
  
        $sql = ("DELETE FROM " . $e->[0] . " WHERE email=?");
        $sth = $dbh->prepare($sql) or die "Prepare Error: $DBI::errstr\n";
        $sth->execute($email) or die "SQL Error: $DBI::errstr\n";
        
        $sql = "INSERT INTO " . $e->[0] . " VALUES(?,?,?,?,?)";
        $sth = $dbh->prepare($sql) or die "Prepare Error: $DBI::errstr\n";
        $sth->execute('NULL',$email,$salutation,$first,$last) 
        or die "SQL Error: $DBI::errstr\n";
  
        $sql = ("DELETE FROM contacts WHERE email=?");
        $sth = $dbh->prepare($sql) or die "Prepare Error: $DBI::errstr\n";
        $sth->execute($email) or die "SQL Error: $DBI::errstr\n";
        last;
      }
      $numberOfEmails++;
    }
    close (inputDat);
  }

1;
}
##


### BAD CONNECTION ATTEMPTS MODULE ###
# GRAB THE IP'S AND DOMAINS FROM BAD CONNECTION ATTEMPTS
# BY PARSING THE PERIODIC DAILY SECURITY REPORT THAT IS EMAILED OUT
# THEN UPDATE THE /etc/hosts.allow FILE TO DENY THEM FOREVER
##
#
# 1) Run regex, build multi-demensional array with lists of unique elements.
# 2) Compare the lists to make a single array of a unique elements.
# 3) Compare that list against a list from a database
# 4) Compare against whitelist
# 5) Add all NEW elements to database and /etc/hosts.allow
#    4a) Add elements to database
#    4b) Form statements for hosts.allow file
#    4c) Test statements for hosts.allow file
#    4d) Create a backup of current host file and the NEW host.allow file
#    4e) Copy the NEW host.allow file over the actual host.allow file
#    4f) Test internet. If it fails, reverse action and notify administrator.
#

sub intrusionMod {
  my $datFile = 0;
  my $i = 0;
  my $j = 0;
  my $jl = 0;
  my $email = 0;
  my $e = 0;
  my $match = 0;
  my @matches = (0);
  my %hash = (0,0);
  my $foo = 0;

  # For every array in the config file, loop through and apply the regex
  # create the tables
  foreach $e (@securityLogErrors){
    $datFile = $e->[0] . ".dat";
    open (badData, ">".$datFile) or die "$!\n";
    open (inputDat, $securityLog) or die "$!\n";
    # Chomp through file and apply regex query
    my $er = $e->[1];
    while (<inputDat>){
      chomp;
      if(m/$er/){
        $match .= $1 . " ";
      }
    }
  
    # Remove Duplicate Matches
    my @array2 = (0);
    $_ = $match;
    @array2 = m/(\S+)/g;
    %hash = map { $_ => 1 } @array2; 
    @array2 = keys %hash;
    
    # Create multi-demensional array with results from all regex matches
    push(@matches, @array2);
    $numBadAddresses = @matches;

    undef @array2;
    close (badData);
    close (inputDat);
  }
  # For debugging, output results to screen
  #print @matches;

1;
}
##


### USER MODULE ###
# CHECKS USER AND PASSWD FILE AGAINST ANOTHER VERSION
##
sub userMod {
# The user module is not yet complete.

1;
}
##


## If cleanDat is on, erase all dat files
##
sub clean {
  if(unlink <*.dat>){
    $successfulClean = 1;
  }

1;
}
##


## Run the modules based on which ones are enabled.
## Print the pass/fail report to screen and output an html file.
if($periodicReportsParser) {
  my $emailModResult = 0;
  my $intrusionModResult = 0;
  my $userModResult = 0;

  if($emailMod){
    $emailModResult = emailMod;
    if($emailModResult){
      print outputDat "\n<b>Email Module ran Successfully</b>\n";
      print outputDat "Total Number of bad emails found: $numberOfEmails\n";
      print "\nEmail Module ran Successfully\n";
    }
    else{
      print outputDat "\n<b>Email Module did not exit properly.</b>\n";
      print "\nEmail Module did not exit properly.\n";
    }
  }
  else{
    print outputDat "\n<b>Email Module is turned off.</b>\n";
    print "\nEmail Module is turned off.\n";
  }
  
  if($intrusionMod){
    $intrusionModResult = intrusionMod;
    if($intrusionModResult){
      print outputDat "\n<b>Intrusion Module ran Successfully</b>\n";
      print outputDat "The number of bad addresses found: ". $numBadAddresses ."\n";
      print "\nIntrusion Module ran Successfully\n";
    }
    else{
      print outputDat "\n<b>Intrusion Module did not exit properly.</b>\n";
      print "\nIntrusion Module did not exit properly.\n";
    }
  }
  else{
    print outputDat "\n<b>Intrusion Module is turned off.</b>\n";
    print "\nIntrusion Module is turned off.\n";
  }
  
  if($userMod){
    $userModResult = userMod;
    if($userModResult){
      print outputDat "\n<b>User Module ran Successfully</b>\n";
      print "\nUser Module ran Successfully\n";
    }
    else{
      print outputDat "\n<b>User Module did not exit properly.</b>\n";
      print "\nUser Module did not exit properly.\n";
    }
  }
  else{
    print outputDat "\n<b>User Module is turned off.</b>\n";
    print "\nUser Module is turned off.\n";
  }
  if($cleanDat == 1){
    my $runClean = clean;
    if($successfulClean){
      print outputDat "\n<b>.dat files were successfully cleaned.</b>\n";
      print "\n.dat files were successfully cleaned.\n";
    }
    else{
      print outputDat "\n<b>.dat files were NOT successfully cleaned.</b>\n";
      print "\n.dat files were NOT successfully cleaned.\n";
    }
  }
  else{
    print outputDat "\n<b>Clean Dat files are off.</b>\n";
    print "\nClean Dat files are off.\n";
  }
}
else{
  print outputDat "\n<b>Periodic Reports Parser is turned off</b>.\n";
  print "\nPeriodic Reports Parser is turned off.\n";
}

print outputDat "<h5><br><a href=\"http://ecastmyhome.com/admin/reports/run.php\" title=\"Run Script\">RUN SCRIPT</a></h5>";
print outputDat "</pre></body></html>";
move("runOutput.html",$reportDir."runOutput.html") 
or die("Could not move html. Make sure that the '$reportDir' exists.");

close(outputDat);

##
